/**
 * Project:   warnme-app
 * File:      MainActivity.java
 * License: 
 *            This file is licensed under GNU General Public License version 3
 *            http://www.gnu.org/licenses/gpl-3.0.txt
 *
 * Copyright: Bartosz Cichecki [ cichecki.bartosz@gmail.com ]
 * Date:      Mar 23, 2014
 */

package dtu.ds.warnme.app.activity;

import org.apache.commons.collections4.queue.CircularFifoQueue;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Header;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Fragment;
import android.app.FragmentTransaction;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.Toast;

import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapFragment;
import com.google.gson.reflect.TypeToken;

import dtu.ds.warnme.app.R;
import dtu.ds.warnme.app.application.Prefs;
import dtu.ds.warnme.app.dialog.LoginDialog;
import dtu.ds.warnme.app.dialog.RegisterDialog;
import dtu.ds.warnme.app.dialog.ReportDialog;
import dtu.ds.warnme.app.dialog.WarningDialog;
import dtu.ds.warnme.app.dialog.listener.LoginDialogListener;
import dtu.ds.warnme.app.dialog.listener.RegisterDialogListener;
import dtu.ds.warnme.app.dialog.listener.ReportDialogListener;
import dtu.ds.warnme.app.holders.UserProfileHolder;
import dtu.ds.warnme.app.location.FollowMeLocationSource;
import dtu.ds.warnme.app.location.FollowMeLocationSourceListener;
import dtu.ds.warnme.app.model.impl.Event;
import dtu.ds.warnme.app.model.impl.User;
import dtu.ds.warnme.app.ws.client.https.GsonHttpResponseHandler;
import dtu.ds.warnme.app.ws.client.restful.RestClientHolder;

/**
 * 
 * @author Bartosz Cichecki
 * 
 */
public class MainActivity extends Activity implements FollowMeLocationSourceListener, LoginDialogListener, RegisterDialogListener,
        ReportDialogListener {

	private static final String TAG = "MainActivity";

	public static final String KEY_CURRENT_LOCATION = "currentLocation";

	public static final String KEY_EVENT = "event";

	private GoogleMap map;

	private FollowMeLocationSource locationSource;

	private Button buttonReport;

	private MenuItem menuItemDesc;

	private MenuItem menuItemLogin;

	private MenuItem menuItemLogout;

	private MenuItem menuItemRegister;

	private WarningDialog warningDialog;

	private CircularFifoQueue<Event> alreadyWarned = new CircularFifoQueue<Event>(100);

	public Button getButtonReport() {
		return buttonReport;
	}

	public MenuItem getMenuItemDesc() {
		return menuItemDesc;
	}

	public MenuItem getMenuItemLogin() {
		return menuItemLogin;
	}

	public MenuItem getMenuItemLogout() {
		return menuItemLogout;
	}

	@Override
	public void onAbort() {
		buttonReport.setEnabled(true);
	}

	@Override
	public void onApproachingEvent(Event event) {
		if (warningDialog != null && event.equals(warningDialog.getEvent())) {
			return;
		}

		if (alreadyWarned.contains(event)) {
			return;
		}
		alreadyWarned.add(event);

		if (warningDialog != null) {
			warningDialog.dismiss();
		}

		FragmentTransaction ft = getFragmentManager().beginTransaction();
		Fragment prev = getFragmentManager().findFragmentByTag(LoginDialog.class.getName());
		if (prev != null) {
			ft.remove(prev);
		}
		ft.addToBackStack(null);

		Bundle args = new Bundle();
		args.putSerializable(KEY_EVENT, event);

		warningDialog = new WarningDialog();
		warningDialog.setEvent(event);
		warningDialog.setArguments(args);
		warningDialog.show(ft, WarningDialog.class.getName());
	}

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

		map = ((MapFragment) getFragmentManager().findFragmentById(R.id.map)).getMap();
		map.setMapType(GoogleMap.MAP_TYPE_NORMAL);
		map.setMyLocationEnabled(true);
		map.getUiSettings().setAllGesturesEnabled(true);
		map.getUiSettings().setCompassEnabled(true);

		locationSource = new FollowMeLocationSource(this, getApplicationContext(), map);
		locationSource.getBestAvailableProvider();
		map.setLocationSource(locationSource);

		buttonReport = (Button) findViewById(R.id.button_report);
		buttonReport.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				buttonReport.setEnabled(false);

				FragmentTransaction ft = getFragmentManager().beginTransaction();
				Fragment prev = getFragmentManager().findFragmentByTag(ReportDialog.class.getName());
				if (prev != null) {
					ft.remove(prev);
				}
				ft.addToBackStack(null);

				Bundle args = new Bundle();
				args.putParcelable(KEY_CURRENT_LOCATION, locationSource.getCurrentLocation());

				ReportDialog reportDialog = new ReportDialog();
				reportDialog.setArguments(args);
				reportDialog.show(ft, ReportDialog.class.getName());
			}
		});

		verifyLogin();
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		getMenuInflater().inflate(R.menu.main, menu);

		menuItemDesc = menu.findItem(R.id.action_desc);
		menuItemLogin = menu.findItem(R.id.action_login);
		menuItemRegister = menu.findItem(R.id.action_register);
		menuItemLogout = menu.findItem(R.id.action_logout);

		updateUserInterface();

		return true;
	}

	@Override
	public void onCredentialsExpired() {
		updateUserInterface();

		AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this);
		dialogBuilder.setIcon(android.R.drawable.ic_dialog_alert).setTitle(R.string.credentials_expired)
		        .setMessage(R.string.credentials_expired_desc)
		        .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {

			        @Override
			        public void onClick(DialogInterface dialog, int which) {
				        // Nothing to do here...
			        }
		        });
		dialogBuilder.show();
	}

	@Override
	protected void onDestroy() {
		super.onDestroy();
		RestClientHolder.getRestClient().cancelRequests(this, true);
	}

	@Override
	public void onDownloadEventsFailed() {
		Toast.makeText(this, R.string.failed_to_update_events, Toast.LENGTH_SHORT).show();
	}

	@Override
	public void onDownloadEventsSuccessful() {
		Toast.makeText(this, R.string.new_events_downloaded, Toast.LENGTH_SHORT).show();
	}

	@Override
	public void onLoginFailure() {
		updateUserInterface();
	}

	@Override
	public void onLoginSuccess() {
		updateUserInterface();
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		int id = item.getItemId();
		if (id == R.id.action_login) {
			Log.d(TAG, "Showing login dialog...");

			FragmentTransaction ft = getFragmentManager().beginTransaction();
			Fragment prev = getFragmentManager().findFragmentByTag(LoginDialog.class.getName());
			if (prev != null) {
				ft.remove(prev);
			}
			ft.addToBackStack(null);

			LoginDialog ld = new LoginDialog();
			ld.show(ft, LoginDialog.class.getName());
			return true;
		}
		if (id == R.id.action_register) {
			Log.d(TAG, "Showing register dialog...");

			FragmentTransaction ft = getFragmentManager().beginTransaction();
			Fragment prev = getFragmentManager().findFragmentByTag(RegisterDialog.class.getName());
			if (prev != null) {
				ft.remove(prev);
			}
			ft.addToBackStack(null);

			RegisterDialog rd = new RegisterDialog();
			rd.show(ft, RegisterDialog.class.getName());
			return true;
		}
		if (id == R.id.action_logout) {
			Log.d(TAG, "Logging out...");

			UserProfileHolder.clear();
			Prefs.setUsername(StringUtils.EMPTY);
			Prefs.setPasswordHash(StringUtils.EMPTY);

			updateUserInterface();
			return true;
		}
		if (id == R.id.action_settings) {
			Log.d(TAG, "Moving to Settings activity...");

			Intent settingsActivityIntent = new Intent(this, SettingsActivity.class);
			startActivity(settingsActivityIntent);
			return true;
		}
		return super.onOptionsItemSelected(item);
	}

	@Override
	public void onRegisterFailure() {
		// Nothing to do here...
	}

	@Override
	public void onRegisterSuccess() {
		Toast.makeText(this, R.string.registration_successful, Toast.LENGTH_LONG).show();
	}

	@Override
	public void onReportFailed() {
		buttonReport.setEnabled(true);
	}

	@Override
	public void onReportSuccessful() {
		buttonReport.setEnabled(true);
		Toast.makeText(this, R.string.report_success, Toast.LENGTH_SHORT).show();
	}

	private void updateUserInterface() {
		Log.d(TAG, "Updating user interface. [loggedIn=" + UserProfileHolder.isLoggedIn() + "]");

		boolean loggedIn = UserProfileHolder.isLoggedIn();

		if (menuItemDesc != null) {
			menuItemDesc.setTitle(UserProfileHolder.getUserProfile() != null ? UserProfileHolder.getUserProfile().getUsername() : "");
		}
		if (menuItemLogin != null) {
			menuItemLogin.setVisible(!loggedIn);
		}
		if (menuItemRegister != null) {
			menuItemRegister.setVisible(!loggedIn);
		}
		if (menuItemDesc != null) {
			menuItemDesc.setVisible(loggedIn);
		}
		if (menuItemLogout != null) {
			menuItemLogout.setVisible(loggedIn);
		}
		if (buttonReport != null) {
			buttonReport.setVisibility(loggedIn ? View.VISIBLE : View.GONE);
		}
	}

	private void verifyLogin() {
		// First let's check if user provided any credentials
		if (Prefs.isCredentialsProvided()) {
			Log.i(TAG, "Verifying stored credentials.");

			// So if user provided some details, let's check if they are correct
			RestClientHolder.getRestClient().getProfile(this, new GsonHttpResponseHandler<User>(new TypeToken<User>() {
			}.getType()) {

				@Override
				public void onFailure(int statusCode, Header[] headers, String responseBody, Throwable error) {
					Log.e(TAG, "Login failed. [statusCode = " + statusCode + ", error=" + error + "]");
					// It seems that details are not correct. Let's disable some UI again.
					updateUserInterface();
				}

				@Override
				public void onFinish() {
					Log.v(TAG, "Automatic login finished.");
				}

				@Override
				public void onStart() {
					Log.i(TAG, "Starting automatic login...");
				}

				@Override
				public void onSuccess(int statusCode, Header[] headers, User user) {
					Log.i(TAG, "Login succeeded. [statusCode=" + statusCode + ", username=" + user.getUsername() + "]");
					// It seems that details that were provided are correct... Let's store the profile and again tweak the UI.
					UserProfileHolder.setUserProfile(user);
					updateUserInterface();
				}
			});

		} else {
			Log.i(TAG, "No credentials stored.");
			// If there are no credentials given let's disable some UI...
			updateUserInterface();
		}
	}

}
